
package stcu;

import stcu.robjects.*;
import com.nvlled.route.*;
import java.net.*;
import java.util.*;

public class Pinger implements Runnable, ObjectReceiver<Ping> {

    private static final int MAX_WAIT = 2000;
    private static final int MAX_TRIES = 2;

    private List<Listener> listeners;
    private boolean running = false;
    private ObjectRouter router;
    private AddressTable table;

    public Pinger(ObjectRouter router) {
        this.router = router;
        table = router.getTable();
        listeners = new LinkedList<Listener>();

        router.subscribe(Ping.class, this);
    }

    public void stop() {
        running = false;
    }

    public void run() {
        running = true;

        while (running) {
            for (String name: table.getNames()) {
                boolean ok = ping(name);
                if (ok) {
                    System.out.println("ping success " + name);
                } else {
                    System.out.println("ping fail " + name);
                }
            }
            Util.nap(20);
        }
    }

    public void receive(Ping ping) {
        System.out.println("Received ping from " + ping.getSourceAddress());
        router.deliver(new Pong(), ping.getSourceAddress());
    }

    public boolean ping(String name) {
        for (int i = 0;i < MAX_TRIES; i++) {
            Pong pong = router.requestOne(new Ping(), Pong.class, 
                    MAX_WAIT, name);
            if (pong != null) {
                return true;
            }
        }

        nodeDown(name);
        return false;
    }

    private void nodeDown(String name) {
        SocketAddress address = table.getAddress(name);

        for (Listener listener: listeners) {
            listener.nodeDown(name, address);
        }
        table.removeNameOnly(name); 
            // note may result in null pointer exception
    }

    public void addListener(Listener listener) {
        if (listener != null) {
            listeners.add(listener);
        }
    }

    public static interface Listener {
        public void nodeDown(String name, SocketAddress address);
    }

}
